package com.knightcloud.common.feign.decoder;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.knightcloud.common.base.vo.response.R;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import org.springframework.http.HttpStatus;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;

/**
 * 通用返回结果解码器
 *
 * @author knight
 */
public class RDecoder implements Decoder {

	private Decoder decoder;

	private ObjectMapper objectMapper;

	public RDecoder(Decoder decoder, ObjectMapper objectMapper) {
		this.decoder = decoder;
		this.objectMapper = objectMapper;
	}

	@Override
	public Object decode(final Response response, Type type) throws IOException, FeignException {
		if (isParameterizeHttpEntity(type)) {
			String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));

			Class actualTypeClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
			return objectMapper.readValue(bodyStr,
					new ObjectMapper().getTypeFactory().constructParametricType(R.class, actualTypeClass));
		}
		else if (isR(type)) {
			return createResponse(null, response);
		}
		else {
			return this.decoder.decode(response, type);
		}
	}

	private boolean isParameterizeHttpEntity(Type type) {
		if (type instanceof ParameterizedType) {
			return isR(((ParameterizedType) type).getRawType());
		}
		return false;
	}

	private boolean isR(Type type) {
		if (type instanceof Class) {
			Class c = (Class) type;
			return R.class.isAssignableFrom(c);
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	private <T> R<T> createResponse(Object instance, Response response) {
		if (Objects.equals(response.status(), HttpStatus.OK.value())) {
			return R.ok((T) instance);
		}
		return R.failed();
	}

}
